package online

import (
	"errors"
	"server/common"

	"github.com/mitchellh/mapstructure"
	"github.com/sirupsen/logrus"
)

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (s *OnlineService) checkCallMakeAckData(data common.CallMakeAckData) error {
	// Check if call ID is provided
	if data.CallId == "" {
		return errors.New("call ID is required in call ack")
	}

	// Check if call exists
	if !s.callMgr.CallExists(data.CallId) {
		return errors.New("call does not exist: " + data.CallId)
	}

	// Check if caller ID is provided
	if data.CallerId == "" {
		return errors.New("caller ID is required in call ack")
	}

	// Check if caller is part of the call
	if !s.callMgr.UserInCall(data.CallId, data.CallerId) {
		return errors.New("caller is not part of the call: " + data.CallId)
	}

	// Check if callee ID is provided
	if data.CalleeId == "" {
		return errors.New("callee ID is required in call ack")
	}

	// Check if call type is valid
	if data.CallType != "p2p" && data.CallType != "p2sp" {
		return errors.New("invalid call type, must be 'p2p' or 'p2sp'")
	}

	return nil
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (s *OnlineService) sendCallReqResponse(rid string, call *CallData, code int, msg string,
	connId string) {
	responseMsg := common.Message{
		Cmd: common.CALL_MAKE_RES,
		Rid: rid,
		Data: common.ResMsgData{
			Code: code,
			Msg:  msg,
			Data: common.CallMakeResData{
				CallId:   call.CallId,
				CalleeId: call.CalleeId,
				CallType: call.CallType,
				CallerId: call.CallerId,
			},
		},
	}

	s.dispatcher.Dispatch(responseMsg, s.serviceInfo, common.AccessServiceInfo, connId)
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (s *OnlineService) handleCallMakeAck(msg common.Message, from common.ServiceInfo,
	connId string) error {
	common.Logger(common.SERVICE_TYPE_ONLINE, msg.Rid).WithFields(logrus.Fields{
		"msg":    common.ToJson(msg),
		"from":   from,
		"connId": connId,
	}).Info("call handleCallAck")

	var resData common.ResMsgData
	if err := mapstructure.Decode(msg.Data, &resData); err != nil {
		LOG(msg.Rid).WithError(err).Error("invalid response data format")
		return nil
	}

	var ackData common.CallMakeAckData
	if err := mapstructure.Decode(resData.Data, &ackData); err != nil {
		LOG(msg.Rid).WithError(err).Error("invalid call ack data format")
		return nil
	}

	if err := s.checkCallMakeAckData(ackData); err != nil {
		LOG(msg.Rid).WithError(err).Error("call ack validation failed")
		return nil
	}

	call, exists := s.callMgr.GetCall(ackData.CallId)
	if !exists {
		LOG(msg.Rid).Errorf("call does not exist: %s", ackData.CallId)
		return nil
	}

	if call.CallState != Calling {
		LOG(msg.Rid).Errorf("call is not in calling state: %s", ackData.CallId)
		return nil
	}

	caller := s.userMgr.GetUserByUserId(call.CallerId)
	if caller == nil {
		LOG(msg.Rid).Errorf("caller not found: %s", call.CallerId)
		return nil
	}

	if resData.Code != 0 {
		s.callMgr.RemoveCall(ackData.CallId)
		s.sendCallReqResponse(msg.Rid, call, resData.Code, resData.Msg, caller.ConnId)
	} else {
		call.CallState = Active
		s.sendCallReqResponse(msg.Rid, call, 0, "call accepted", caller.ConnId)
	}

	return nil
}
